﻿''============================================================================
''PTIC_gestBDD - Composants de requetage / manipulation des bases de données
''Copyright © 2010 PIERRE TISSOT CONSEIL
''=============================================================================

Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Collections.Generic
Imports System.ComponentModel

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
<Serializable()> Public Class Correspondance
    Inherits PTIC_Util.BaseNotifyPropertyChangeComponentModel

#Region "Variables de classe"

    'Description de la correspondance
    Protected _description As String
    'Champs en entrée de la correspondance (nom de champs dans la table physique ou constante)
    Protected _chEntree As ChampsBDD
    'Champs en sortie de la correspondance
    Protected _chSortie As ChampsBDD
    'Objet assurant la liaison entre le format du champs en entrée et celui du champs en sortie
    Protected _informat As informatChampsBDD
    'Possibilité d'utiliser la correspondance comme variable de segmentation pour l'étude
    Protected _possSeg As Boolean
    'DataTable contenant les contraintes sur les valeurs en sortie de la correspondance
    Protected _contraintesVal As DataTable
    'Type de champs paramétré en entrée
    Protected _typeChEntree As typeChEntreeMapping

    'Nom du traitement auquel est rattaché la correspondance
    <NonSerialized()> Protected _traitement As Traitement

    'Liste des correspondances intervenant dans la formule de calcul de la correspondance
    'Cette collection n'est renseignée que dans le cas d'une correspondance calculée
    <NonSerialized()> Protected _lCorrespFormule As List(Of Correspondance)
    'Correspondances constitutives ne sont utiles que pour les correspondances calculés
    <NonSerialized()> Protected _lCorrespConstitutives As List(Of Correspondance)

    'Etat de la correspondance (Rouge / Vert)
    <NonSerialized()> Protected _EtatCorresp As Color
    'Commentaire sur l'état de validité de la correspondance
    <NonSerialized()> Protected _commentaire As String
    'Représentation de l'état de validité de la correspondance
    <NonSerialized()> Protected _btnEtatCorresp As Button

#End Region

#Region "Constructeurs"

    ''' <summary>
    ''' Permet de créer une correspondance vide.
    ''' Constructeur réservé à la classe pour effectuer les copies
    ''' </summary>
    Protected Sub New(ByVal trait As Traitement, ByVal description As String)
        _traitement = trait
        _description = description
        _chEntree = Nothing
        _chSortie = Nothing
        _informat = Nothing
        _contraintesVal = Nothing
        _possSeg = True
        _commentaire = ""
        _btnEtatCorresp = Nothing
        MAJ_EtatCorresp()
    End Sub

    ''' <summary>
    ''' Permet de créer une correpondance à partir de son champs côté BDD
    ''' Une valeur constante est considérée comme constante également côté BDD
    ''' </summary>
    Protected Friend Sub New(ByVal trait As Traitement, _
                             ByVal description As String, _
                             ByVal chEntree As ChampsBDD, _
                             ByVal typeChEntree As typeChEntreeMapping)
        _traitement = trait
        _description = description
        setChEntree(chEntree)
        _typeChEntree = typeChEntree
        _contraintesVal = Nothing
        _possSeg = True
        MAJ_EtatCorresp()
    End Sub

    ''' <summary>
    ''' Permet de créer une correspondance à partir de son champs côté Outil
    ''' </summary>
    ''' <param name="description"></param>
    ''' <param name="chSortie"></param>
    ''' <remarks></remarks>
    Protected Friend Sub New(ByVal trait As Traitement, _
                             ByVal description As String, _
                             ByVal chSortie As ChampsBDD)
        _traitement = trait
        _description = description
        setChSortie(chSortie)
        _typeChEntree = typeChEntreeMapping.NON_INITIALISE
        _contraintesVal = Nothing
        _possSeg = True
        MAJ_EtatCorresp()
    End Sub

#End Region

#Region "Propriétés"

    ''' <summary>
    ''' Description de la correspondance
    ''' </summary>
    Public Property description() As String
        Get
            Return _description
        End Get
        Protected Friend Set(ByVal descr As String)
            OnPropertyChanging("description")
            _description = descr
            OnPropertyChanged("description")
        End Set
    End Property

    ''' <summary>
    ''' Traitement auquel est rattachée la correspondance
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property traitement() As Traitement
        Get
            Return _traitement
        End Get
    End Property

    ''' <summary>
    ''' Renvoie le champs côté Base de données de la correspondance
    ''' </summary>
    Public ReadOnly Property chBDD() As ChampsBDD
        Get
            Return _chEntree
        End Get
    End Property

    ''' <summary>
    ''' Renvoie le champs côté outil de la correspondance
    ''' </summary>
    Public ReadOnly Property chOutil() As ChampsBDD
        Get
            Return _chSortie
        End Get
    End Property

    ''' <summary>
    ''' Revoie l'informat de la correspondance
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property informat() As informatChampsBDD
        Get
            Return _informat
        End Get
        Private Set(ByVal value As informatChampsBDD)
            OnPropertyChanging("informat")
            _informat = value
            OnPropertyChanged("informat")
        End Set
    End Property

    ''' <summary>
    ''' Renvoie l'état de la correspondance
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property etat() As Color
        Get
            Return _EtatCorresp
        End Get
        Private Set(ByVal Value As Color)
            _EtatCorresp = Value
            Dim e As New GenerateCorrespEventArgs(Me.description)
            RaiseEvent EtatChanged(Me, e)
            OnPropertyChanged("etat")
        End Set
    End Property

    ''' <summary>
    ''' Renvoie un descriptif des causes de l'état de la correspondance
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property commentaire() As String
        Get
            Return _commentaire
        End Get
    End Property

    ''' <summary>
    ''' Renvoie le code SQL associé à la correspondance lors de son utilisation dans une requête
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Protected Friend Overridable ReadOnly Property codeSQLSELECT(Optional ByVal withCible As Boolean = True) As String
        Get
            Dim strQuerySELECT As String = ""
            If _lCorrespFormule Is Nothing Then
                strQuerySELECT = strQuerySELECT & _
                        IIf(typeChEntree = typeChEntreeMapping.TABLE, chBDD.Nom, "'" & chBDD.Nom & "'") & _
                        " AS " & chOutil.Nom
            Else
                strQuerySELECT = chBDD.Nom
                For i As Integer = 0 To _lCorrespFormule.Count - 1
                    If _lCorrespFormule(i).typeChEntree <> typeChEntreeMapping.CONSTANT Then
                        If TypeOf (_lCorrespFormule(i).traitement) Is tableBDD Then
                            If _lCorrespFormule(i).traitement.TempNom <> "" Then
                                strQuerySELECT = strQuerySELECT.Replace("{" & CStr(i + 1) & "}", _
                                    _lCorrespFormule(i).traitement.TempNom & "." & _lCorrespFormule(i).chBDD.Nom)
                            Else
                                strQuerySELECT = strQuerySELECT.Replace("{" & CStr(i + 1) & "}", _
                                    _lCorrespFormule(i).chBDD.Nom)
                            End If
                        Else
                            If _lCorrespFormule(i).traitement.TempNom <> "" Then
                                strQuerySELECT = strQuerySELECT.Replace("{" & CStr(i + 1) & "}", _
                                    _lCorrespFormule(i).traitement.TempNom & "." & _lCorrespFormule(i).chOutil.Nom)
                            Else
                                strQuerySELECT = strQuerySELECT.Replace("{" & CStr(i + 1) & "}", _
                                    _lCorrespFormule(i).chOutil.Nom)
                            End If
                        End If
                    Else
                        If TypeOf (_lCorrespFormule(i).traitement) Is tableBDD Then
                            strQuerySELECT = strQuerySELECT.Replace("{" & CStr(i + 1) & "}", _
                                   "'" & _lCorrespFormule(i).chBDD.Nom & "'")
                        Else
                            If _lCorrespFormule(i).traitement.TempNom <> "" Then
                                strQuerySELECT = strQuerySELECT.Replace("{" & CStr(i + 1) & "}", _
                                   _lCorrespFormule(i).traitement.TempNom & "." & _lCorrespFormule(i).chOutil.Nom)
                            Else
                            End If
                        End If
                    End If
                Next
                If withCible Then strQuerySELECT = strQuerySELECT & " AS " & chOutil.Nom
            End If
            Return strQuerySELECT
        End Get
    End Property

    ''' <summary>
    ''' Renvoie le code SQL associé à la correspondance lors de son utilisation dans une requête
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Protected Friend Overridable ReadOnly Property codeSQLGROUPBY() As String
        Get
            Dim strQueryGROUPBY As String = ""
            If _lCorrespFormule Is Nothing Then
                strQueryGROUPBY = strQueryGROUPBY & _
                    IIf(typeChEntree = typeChEntreeMapping.TABLE, chBDD.Nom & ",", "")
            Else
                strQueryGROUPBY = chBDD.Nom
                For i As Integer = 0 To _lCorrespFormule.Count - 1
                    If _lCorrespFormule(i).typeChEntree <> typeChEntreeMapping.CONSTANT Then
                        If TypeOf (_lCorrespFormule(i).traitement) Is tableBDD Then
                            strQueryGROUPBY = strQueryGROUPBY.Replace("{" & CStr(i + 1) & "}", _
                                                                    _lCorrespFormule(i).chBDD.Nom)
                        Else
                            strQueryGROUPBY = strQueryGROUPBY.Replace("{" & CStr(i + 1) & "}", _
                                        _lCorrespFormule(i).chOutil.Nom)
                        End If
                    Else
                        If TypeOf (_lCorrespFormule(i).traitement) Is tableBDD Then
                            strQueryGROUPBY = strQueryGROUPBY.Replace("{" & CStr(i + 1) & "}", _
                                                                    "'" & _lCorrespFormule(i).chBDD.Nom & "'")
                        Else
                            strQueryGROUPBY = strQueryGROUPBY.Replace("{" & CStr(i + 1) & "}", _
                                        _lCorrespFormule(i).chOutil.Nom)
                        End If
                    End If
                Next
            End If
            Return strQueryGROUPBY
        End Get
    End Property

    ''' <summary>
    ''' Possibilité de retenir la correspondance comme variable de segmentation
    ''' </summary>
    Public Property possSeg() As Boolean
        Get
            Return _possSeg
        End Get
        Set(ByVal value As Boolean)
            _possSeg = value
            OnPropertyChanged("possSeg")
        End Set
    End Property

    ''' <summary>
    ''' Type de champs en entrée de la correspondance (issu de la table source ou constant)
    ''' </summary>
    Public Property typeChEntree() As typeChEntreeMapping
        Get
            Return _typeChEntree
        End Get
        Set(ByVal value As typeChEntreeMapping)
            _typeChEntree = value
            RaiseEvent TypeChampsEntreeChanged(Me, New EventArgs)
            OnPropertyChanged("typeChEntree")
        End Set
    End Property

    ''' <summary>
    ''' Table des valeurs attendues de la correspondance
    ''' </summary>
    Public Property ContraintesVal As DataTable
        Get
            Return _contraintesVal
        End Get
        Set(ByVal value As DataTable)
            OnContraintesValChanging()
            _contraintesVal = value
            OnContraintesValChanged()
        End Set
    End Property
    Protected Sub OnContraintesValChanged()
        OnPropertyChanged("ContraintesVal")
        MAJ_EtatCorresp()
    End Sub
    Protected Sub OnContraintesValChanging()
        OnPropertyChanging("ContraintesVal")
    End Sub

#End Region

#Region "Méthodes"

    ''' <summary>
    ''' Permet de paramétrer le champs en entrée de la correspondance
    ''' </summary>
    Public Function setChEntree(ByVal chEntree As ChampsBDD) As Boolean
        Dim result As Boolean = False
        Dim aEteModifie As Boolean = False
        If chEntree Is Nothing Then
            _chEntree = Nothing
            aEteModifie = True
            informat = Nothing
            typeChEntree = typeChEntreeMapping.NON_INITIALISE
            MAJ_EtatCorresp()
            result = True
        Else
            If _chSortie Is Nothing Then
                _chEntree = chEntree
                aEteModifie = True
                'Le champs en entrée est copié pour éviter les effets de bord
                _chSortie = chEntree.copy()
                'On donne au champs en sortie un format compatible avec celui du champs en entrée
                _chSortie.Format = informatChampsBDD.getFormatSortieDefaut(_chEntree.Format)
                'Redéfinition de l'informat
                _informat = New informatChampsBDD(_chEntree.Format, _chSortie.Format)
                If _informat.nom = "-" And Not _chEntree.valeursDistinctes Is Nothing Then
                    _chSortie.valeursDistinctes = _chEntree.valeursDistinctes
                Else
                    _chSortie.valeursDistinctes = Nothing
                End If
                MAJ_EtatCorresp()
                result = True
            Else
                If informatChampsBDD.sontCompatibles(chEntree.Format, _chSortie.Format) Then
                    _chEntree = chEntree
                    aEteModifie = True
                    'Redéfinition de l'informat
                    informat = New informatChampsBDD(_chEntree.Format, _chSortie.Format)
                    If informat.nom = "-" And Not _chEntree.valeursDistinctes Is Nothing Then
                        _chSortie.valeursDistinctes = _chEntree.valeursDistinctes
                    Else
                        _chSortie.valeursDistinctes = Nothing
                    End If
                    MAJ_EtatCorresp()
                    result = True
                Else
                    MsgBox("Le format du champs en entrée que vous tentez d'importer n'est pas compatible avec le champs attendu en sortie")
                End If
            End If
        End If
        'Génération de l'évènement "le champs en entrée de la correspondance a été changé"
        If aEteModifie Then
            OnPropertyChanged("chBDD")
            Dim e As GenerateCorrespEventArgs = New GenerateCorrespEventArgs(Me.description)
            RaiseEvent ChampsSourceChanged(Me, e)
            correspHasChanged()
        End If
        Return result
    End Function

    ''' <summary>
    ''' Permet de paramétrer le champs en sortie de la correspondance
    ''' </summary>
    Protected Friend Function setChSortie(ByVal chSortie As ChampsBDD) As Boolean
        Dim result As Boolean = False
        If Not _chEntree Is Nothing Then
            'Vérifier qu'il existe un informat permettant de convertir le format source
            'en fomat cible
            If informatChampsBDD.sontCompatibles(_chEntree.Format, chSortie.Format) Then
                _chSortie = chSortie
                OnPropertyChanged("chOutil")
                _informat = New informatChampsBDD(_chEntree.Format, _chSortie.Format)
                MAJ_EtatCorresp()
                result = True
            Else
                MsgBox("Le format du champs en sortie que vous tentez de paramétrer n'est pas n'est pas compatbile avec le champs source de la correspondance")
            End If
        Else
            _chSortie = chSortie
            OnPropertyChanged("chOutil")
            'Aucun informat n'est créé car aucun champs source n'est paramétré sur la correspondance
            MAJ_EtatCorresp()
            result = True
        End If
        Return result
    End Function

    ''' <summary>
    ''' Permet de paramétrer le traitement auquel est rattachée la correspondance
    ''' </summary>
    ''' <param name="trait"></param>
    ''' <remarks></remarks>
    Protected Friend Sub setTraitement(ByVal trait As Traitement)
        Me._traitement = trait
        OnPropertyChanged("traitement")
    End Sub

    ''' <summary>
    ''' Met à jour l'état de la correspondance
    ''' </summary>
    Public Sub MAJ_EtatCorresp()

        'Cette fonction permet de mettre à jour la validité de la correspondance paramétrée
        Dim result As Color
        result = Color.Green

        _commentaire = ""

        'Test si un champs source a bien été affecté à la correspondance
        If _chEntree Is Nothing And Not (_chSortie Is Nothing) Then
            _commentaire = "- Aucune valeure n'est affectée au champs source." & vbCrLf
            result = Color.Red
        End If

        'Test la validité des correspondances intervenant dans la formule de calcul.
        'Si l'une d'entre elles est invalide, la correspondance est invalidée
        If Not _lCorrespFormule Is Nothing Then
            If _lCorrespFormule.Count <> 0 Then
                For Each corresp As Correspondance In _lCorrespFormule
                    If corresp.etat <> Color.Green Then
                        _commentaire = _commentaire & "- L'une des correspondances intervenant dans la formule de calcul est invalide."
                        result = Color.Red
                    End If
                Next
            End If
        End If

        'Test l'adéquation des valeurs sources avec les valeurs attendues à ajouter
        If _commentaire = "" Then _commentaire = "OK"
        If Not (etat.G = result.G And etat.R = result.R And etat.B = result.B) Then
            etat = result
        End If
        If Not (_btnEtatCorresp Is Nothing) Then
            _btnEtatCorresp.BackColor = result
        End If
    End Sub

    ''' <summary>
    ''' Renvoie une copie de la correspondance
    ''' </summary>
    Public Function copy() As Correspondance

        'Copie des champs en entrée et en sortie de la correspondance
        Dim chEntreeClone, chSortieClone As ChampsBDD
        If Not _chEntree Is Nothing Then chEntreeClone = _chEntree.copy() Else chEntreeClone = Nothing
        If Not _chSortie Is Nothing Then chSortieClone = _chSortie.copy() Else chSortieClone = Nothing

        'Copie de l'informat de la correspondance
        Dim informatClone As informatChampsBDD
        If Not _informat Is Nothing Then informatClone = New informatChampsBDD(chEntreeClone.Format, chSortieClone.Format, _informat.nom) Else informatClone = Nothing

        'Copie des contraintes sur les valeurs de la correspondance
        Dim contraintesValClone As DataTable
        If Not _contraintesVal Is Nothing Then contraintesValClone = _contraintesVal.Copy Else contraintesValClone = Nothing

        'Copie de la correspondance
        Dim correspondanceClone As New Correspondance(_traitement, _description)
        correspondanceClone._chEntree = chEntreeClone
        correspondanceClone._chSortie = chSortieClone
        correspondanceClone._informat = informatClone
        correspondanceClone._contraintesVal = contraintesValClone
        correspondanceClone._possSeg = _possSeg
        correspondanceClone._typeChEntree = _typeChEntree
        If Not _lCorrespConstitutives Is Nothing Then
            For Each corresp As Correspondance In _lCorrespConstitutives
                correspondanceClone.addCorrespConstitutive(corresp)
            Next
        End If
        If Not _lCorrespFormule Is Nothing Then
            For Each corresp As Correspondance In _lCorrespFormule
                correspondanceClone.addCorrespFormule(corresp)
            Next
        End If
        correspondanceClone._commentaire = _commentaire
        correspondanceClone._btnEtatCorresp = _btnEtatCorresp
        correspondanceClone.MAJ_EtatCorresp()

        Return correspondanceClone

    End Function

#End Region

#Region "Méthodes de gestion des dépendances entre correspondances"

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Protected Sub correspHasChanged()
        RaiseEvent CorrespChanged(Me, New GenerateCorrespEventArgs(Me.description))
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub addCorrespConstitutive(ByVal correspConstitutive As Correspondance)
        If _lCorrespConstitutives Is Nothing Then _lCorrespConstitutives = New List(Of Correspondance)
        If Not _lCorrespConstitutives.Contains(correspConstitutive) Then
            _lCorrespConstitutives.Add(correspConstitutive)
            AddHandler correspConstitutive.CorrespChanged, AddressOf onCorrespConstitutiveHasChanged
            AddHandler correspConstitutive.EtatChanged, AddressOf onEtatCorrespConstitutiveHasChanged
            MAJ_EtatCorresp()
        End If
    End Sub
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub addCorrespFormule(ByVal correspFormule As Correspondance)
        If _lCorrespFormule Is Nothing Then _lCorrespFormule = New List(Of Correspondance)
        If Not _lCorrespFormule.Contains(correspFormule) Then
            _lCorrespFormule.Add(correspFormule)
            addCorrespConstitutive(correspFormule)
        End If
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub clearCorrespConstitutive()
        If Not _lCorrespConstitutives Is Nothing Then _lCorrespConstitutives.Clear()
        MAJ_EtatCorresp()
    End Sub
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub clearCorrespFormule()
        If Not _lCorrespFormule Is Nothing Then _lCorrespFormule.Clear()
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Protected Overridable Sub onEtatCorrespConstitutiveHasChanged(ByVal sender As Object, _
                                                                  ByVal e As GenerateCorrespEventArgs)
        MAJ_EtatCorresp()
    End Sub
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Protected Overridable Sub onCorrespConstitutiveHasChanged(ByVal sender As Object, ByVal e As GenerateCorrespEventArgs)
        'Lorsque l'une des correspondances constitutive est invalidée, la correspondance est également invalidée
        RaiseEvent CorrespChanged(Me, New GenerateCorrespEventArgs(Me.description))
    End Sub

#End Region

#Region "Serialization"

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Function estSerializeCompatible(ByVal corresp As Correspondance) As Boolean

        Dim result As Boolean = True

        If _chSortie.Format.typeStock.Name <> corresp.chOutil.Format.typeStock.Name Then result = False
        If _chSortie.Format.typeAff.Name <> corresp.chOutil.Format.typeAff.Name Then result = False
        If _chSortie.Nom <> corresp.chOutil.Nom Then result = False

        If _description <> corresp.description Then result = False

        Return result

    End Function

#End Region

#Region "Evènements"

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub invalidate()
        RaiseEvent ChampsSourceChanged(Me, New GenerateCorrespEventArgs(Me.description))
    End Sub

    Protected Sub RaiseEventCorrespChanged(ByVal sender As Object, ByVal e As PTIC_GestionBDD.GenerateCorrespEventArgs)
        RaiseEvent CorrespChanged(sender, e)
    End Sub

    'Déclaration du délégué, type des évènements
    Public Delegate Sub correspGeneratedEventHandler(ByVal sender As Object, ByVal e As GenerateCorrespEventArgs)

    'Déclaration des évènements
    Public Event TypeChampsEntreeChanged As EventHandler
    Public Event EtatChanged As correspGeneratedEventHandler
    Public Event ChampsSourceChanged As correspGeneratedEventHandler
    Public Event CorrespChanged As correspGeneratedEventHandler

#End Region

End Class